package csm.common;

import java.text.MessageFormat;
import java.util.ArrayList;

public final class StringUtil
{
    /**
     * 빈문자열
     */
    public static final String EMPTY = "";


    /**
     * 서식을 사용한 문자열을 작성합니다.<br>
     * <pre>
     * StringUtil.format("That is {0}!! {1}, do you like {0}?", "apple", "sam");
     *
     *  --> That is <b>apple</b>!! <b>sam</b>, do you like <b>apple</b>?
     * </pre>
     * @param pattern
     * @param arguments
     * @return
     */
    public static String format(String pattern, Object... arguments){
        return MessageFormat.format(pattern, arguments);
    }

    /**
     * 주어진 문자열이 <code>Null</code>이거나 빈 문자열인지 검사합니다.
     *
     * @param str
     * @return true : 주어진 문자열이 <code>Null</code>이거나 빈 문자열입니다
     */
    public static boolean isNullOrEmpty(String str)
    {
        return str == null || str.length() == 0;
    }

    /**
     * 주어진 문자열의 앞/뒤의 공백을 제거합니다.<br>
     * 만일 주어진 문자열이 <code>Null</code>인경우 <code>""</code> 문자열을 반환합니다.
     *
     * @param str
     * @return
     */
    public static String trim(String str)
    {
        return StringUtil.isNullOrEmpty(str) ? EMPTY : str.trim();
    }

    /**
     * 지정한 문자열에서 특정 문자/문자열이 존재합니까?<br>
     * 대소문자를 구별합니다.
     * @param str 탐색대상 문자열
     * @param searchStr 탐색대상 문자열에서 찾을 문자/문자열
     * @return
     */
    public static boolean contains(String str, String searchStr) {
        if (str == null || searchStr == null)
            return false;

        return str.indexOf(searchStr) >= 0;
    }

    /**
     * 문자열의 가장 좌측에서 지정된 길이만큼 잘라서 반환합니다.
     * @param str 가공할 문자열
     * @param len 잘라 낼 길이<br>가공할 문자열의 길이보다 길면, 가공할 문자열을 그대로 반환합니다.
     * @return
     */
    public static String left(String str, int len) {
        if (str == null)
            return null;

        if (len < 0)
            return EMPTY;

        if (str.length() <= len)
            return str;

        return str.substring(0, len);
    }

    /**
     * 문자열의 가장 우측에서 지정된 길이만큼 잘라서 리턴합니다.
     *
     * @param str 가공할 문자열
     * @param len 잘라 낼 길이<br>가공할 문자열의 길이보다 길면, 가공할 문자열을 그대로 반환합니다.
     * @return
     */
    public static String right(String str, int len)
    {
        if (str == null)
            return null;

        if (len < 0)
            return EMPTY;

        if (str.length() <= len)
            return str;

        return str.substring(str.length() - len);
    }

    /**
     * 주어진 길이 만큼 문자열의 좌측을 채워넣는다.<br>
     * 문자열이 지정한 길이보다 길다면 잘라낸다.<br>
     * 넘어온 문자열이 <code>Null</code>인 경우에도 처리되도록 수정.
     *
     * @param str 가공대상이 되는 문자열
     * @param len 반복할 문자 수
     * @param c 반복할 문자
     */
    public static String padl(String str, int len, char c)
    {
        if (str == null)
            str = EMPTY;

        StringBuffer sb = new StringBuffer(str.length() + len);

        int i = Math.min(str.length(), len);

        sb.append(str.substring(0, i));
        i = len - i;

        while (i > 0)
        {
            sb.insert(0, c);
            i--;
        }

        return sb.toString();
    }

    /**
     * 주어진 길이 만큼 문자열의 우측을 채워넣는다.<br>
     * 문자열이 지정한 길이보다 길다면 잘라낸다.<br>
     * 넘어온 문자열이 <code>Null</code>인 경우에도 처리되도록 수정.
     *
     * @param str
     * @param len
     * @param c
     */
    public static String padr(String str, int len, char c)
    {
        if (str == null)
            str = EMPTY;

        StringBuffer sb = new StringBuffer(str.length() + len);

        int i = Math.min(str.length(), len);

        sb.append(str.substring(0, i));
        i = len - i;

        while (i > 0)
        {
            sb.append(c);
            i--;
        }
        return sb.toString();
    }

    /**
     * 주어진 문자열이 <code>Null</code>이거나 빈 문자열이면, <code>defaultString</code>을 반환합니다.
     *
     * @param str
     * @param defaultString
     * @return
     */
    public static String nvl(String str, String defaultString)
    {
        if (StringUtil.isNullOrEmpty(str))
            return defaultString;
        return str;
    }

    /**
     * 문자열의 길이를 반환합니다.
     * @param str 검사할 문자열 <br> 만일 <code>Null</code>이면 <code>0</code>을 반환합니다.
     * @return
     */
    public static int length( String str ){
        return nvl(str, EMPTY).length();
    }



    /**
     * 문자열에서 특정 문자열을 찾아 치환합니다.
     * @param str 처리대상 문자/문자열
     * @param searchString 찾을 문자/문자열
     * @param replacement 대체할 문자/문자열
     * @return
     */
    public static String replace(String str, String searchString, String replacement)
    {
        if (isNullOrEmpty(str) || isNullOrEmpty(searchString) || isNullOrEmpty(replacement))
            return str;

        int index = 0;
        StringBuffer buf = new StringBuffer(str.length());
        while ((index = str.indexOf(searchString, index)) != -1)
        {
            //buf = new StringBuffer(str);
            buf.append(str);
            buf.replace(index, index + searchString.length(), replacement);
            index = index + replacement.length();
            str = buf.toString();
            buf.setLength(0);
        }
        return str;
    }

    /**
     * 문자열에서 지정된 회수만큼 특정 문자열을 치환합니다.
     *
     * @param str 처리대상 문자/문자열
     * @param searchString 찾을 문자/문자열
     * @param replacement 대체할 문자/문자열
     * @param max 반복횟수 (<code>0</code>이거나, 음수이면 진행하지 않고, 가공되지 않은 문자열을 반환)
     * @return 치환된 문자열
     */
    public static String replace(String str, String searchString, String replacement, int max)
    {
        if (isNullOrEmpty(str) || isNullOrEmpty(searchString) || isNullOrEmpty(replacement) || max <= 0)
            return str;

        StringBuffer buf = new StringBuffer(str.length());
        int start = 0, end = 0;
        while ((end = str.indexOf(searchString, start)) != -1)
        {
            buf.append(str.substring(start, end)).append(replacement);
            start = end + searchString.length();
            if (--max == 0)
                break;
        }
        buf.append(str.substring(start));
        return buf.toString();
    }

    /**
     * 문자열중에서 <code>searchString</code>을 전부 <code>replacement</code>으로 치환한다.
     *
     * @param str 처리대상 문자/문자열
     * @param searchString 찾을 문자/문자열
     * @param replacement 대체할 문자/문자열
     * @return 치환된 문자열
     */
    public static String replaceAll(String str, String searchString, String replacement)
    {
        if (isNullOrEmpty(str) || isNullOrEmpty(searchString) || isNullOrEmpty(replacement))
            return str;

        int index = 0;
        StringBuffer buf = new StringBuffer(str.length());
        while ((index = str.indexOf(searchString, index)) != -1)
        {
            // buf = new StringBuffer(str);
            buf.append(str);
            buf.replace(index, index + searchString.length(), replacement);
            str = buf.toString();
            buf.setLength(0);;
        }
        return str;
    }

    /**
     * 구분자로 <code>WhiteSpace</code>를 사용하여 문자열을 나눠줍니다.
     *
     * @param str
     * @return
     */
    public static String[] split(String str)
    {
        return split(str, null, -1);
    }

    /**
     * 지정된 문자로 문자열을 나눠줍니다.
     *
     * @param str
     * @param separatorChars 구분자
     * @return
     */
    public static String[] split(String str, String separatorChars)
    {
        return splitWorker(str, separatorChars, -1, false);
    }

    /**
     * 지정된 문자열에 있는 문자 단위로 문자열을 나눠줍니다.(지정된 개수만큼)
     *
     * @param str
     * @param separatorChars
     * @param max
     * @return
     */
    public static String[] split(String str, String separatorChars, int max)
    {
        return splitWorker(str, separatorChars, max, false);
    }

    /**
     *
     * @param str
     * @param separatorChars
     * @param max
     * @param preserveAllTokens
     * @return
     */
    private static String[] splitWorker(String str, String separatorChars, int max, boolean preserveAllTokens)
    {
        if (str == null)
            return null;

        int len = str.length();
        if (len == 0)
            return new String[] {};

        ArrayList<String> list = new ArrayList<String>();

        int sizePlus1 = 1;
        int i = 0, start = 0;
        boolean match = false;
        boolean lastMatch = false;

        if (separatorChars == null)
        {
            // Null separator means use whitespace
            while (i < len)
            {
                if (Character.isWhitespace(str.charAt(i)))
                {
                    if (match || preserveAllTokens)
                    {
                        lastMatch = true;
                        if (sizePlus1++ == max)
                        {
                            i = len;
                            lastMatch = false;
                        }
                        list.add(str.substring(start, i));
                        match = false;
                    }
                    start = ++i;
                    continue;
                }
                else
                {
                    lastMatch = false;
                }
                match = true;
                i++;
            }
        }
        else if (separatorChars.length() == 1)
        {
            // Optimise 1 character case
            char sep = separatorChars.charAt(0);
            while (i < len)
            {
                if (str.charAt(i) == sep)
                {
                    if (match || preserveAllTokens)
                    {
                        lastMatch = true;
                        if (sizePlus1++ == max)
                        {
                            i = len;
                            lastMatch = false;
                        }
                        list.add(str.substring(start, i));
                        match = false;
                    }
                    start = ++i;
                    continue;
                }
                else
                {
                    lastMatch = false;
                }
                match = true;
                i++;
            }
        }
        else
        {
            // standard case
            while (i < len)
            {
                if (separatorChars.indexOf(str.charAt(i)) >= 0)
                {
                    if (match || preserveAllTokens)
                    {
                        lastMatch = true;
                        if (sizePlus1++ == max)
                        {
                            i = len;
                            lastMatch = false;
                        }
                        list.add(str.substring(start, i));
                        match = false;
                    }
                    start = ++i;
                    continue;
                }
                else
                {
                    lastMatch = false;
                }
                match = true;
                i++;
            }
        }
        if (match || (preserveAllTokens && lastMatch))
        {
            list.add(str.substring(start, i));
        }
        return (String[]) list.toArray(new String[list.size()]);
    }
}
